/*******************************************************************************
 * Copyright (c) 2011 MadRobot.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *  Elton Kent - initial API and implementation
 ******************************************************************************/
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.madrobot.io.file;

import java.io.File;
import java.io.IOException;

/**
 * Strategy for deleting files.
 * <p>
 * There is more than one way to delete a file. You may want to limit access to
 * certain directories, to only delete directories if they are empty, or maybe
 * to force deletion.
 * <p>
 * This class captures the strategy to use and is designed for user subclassing.
 * 
 */
class FileDeleteStrategy {

	/**
	 * The singleton instance for normal file deletion, which does not permit
	 * the deletion of directories that are not empty.
	 */
	public static final FileDeleteStrategy NORMAL = new FileDeleteStrategy("Normal");
	/**
	 * The singleton instance for forced file deletion, which always deletes,
	 * even if the file represents a non-empty directory.
	 */
	public static final FileDeleteStrategy FORCE = new ForceFileDeleteStrategy();

	/** The name of the strategy. */
	private final String name;

	// -----------------------------------------------------------------------
	/**
	 * Restricted constructor.
	 * 
	 * @param name
	 *            the name by which the strategy is known
	 */
	protected FileDeleteStrategy(String name) {
		this.name = name;
	}

	// -----------------------------------------------------------------------
	/**
	 * Deletes the file object, which may be a file or a directory.
	 * All <code>IOException</code>s are caught and false returned instead.
	 * If the file does not exist or is null, true is returned.
	 * <p>
	 * Subclass writers should override {@link #doDelete(File)}, not this
	 * method.
	 * 
	 * @param fileToDelete
	 *            the file to delete, null returns true
	 * @return true if the file was deleted, or there was no such file
	 */
	public boolean deleteQuietly(File fileToDelete) {
		if((fileToDelete == null) || (fileToDelete.exists() == false)){
			return true;
		}
		try{
			return doDelete(fileToDelete);
		} catch(IOException ex){
			return false;
		}
	}

	/**
	 * Deletes the file object, which may be a file or a directory.
	 * If the file does not exist, the method just returns.
	 * <p>
	 * Subclass writers should override {@link #doDelete(File)}, not this
	 * method.
	 * 
	 * @param fileToDelete
	 *            the file to delete, not null
	 * @throws NullPointerException
	 *             if the file is null
	 * @throws IOException
	 *             if an error occurs during file deletion
	 */
	public void delete(File fileToDelete) throws IOException {
		if(fileToDelete.exists() && (doDelete(fileToDelete) == false)){
			throw new IOException("Deletion failed: " + fileToDelete);
		}
	}

	/**
	 * Actually deletes the file object, which may be a file or a directory.
	 * <p>
	 * This method is designed for subclasses to override. The implementation
	 * may return either false or an <code>IOException</code> when deletion
	 * fails. The {@link #delete(File)} and {@link #deleteQuietly(File)} methods
	 * will handle either response appropriately. A check has been made to
	 * ensure that the file will exist.
	 * <p>
	 * This implementation uses {@link File#delete()}.
	 * 
	 * @param fileToDelete
	 *            the file to delete, exists, not null
	 * @return true if the file was deleteds
	 * @throws NullPointerException
	 *             if the file is null
	 * @throws IOException
	 *             if an error occurs during file deletion
	 */
	protected boolean doDelete(File fileToDelete) throws IOException {
		return fileToDelete.delete();
	}

	// -----------------------------------------------------------------------
	/**
	 * Gets a string describing the delete strategy.
	 * 
	 * @return a string describing the delete strategy
	 */
	@Override
	public String toString() {
		return "FileDeleteStrategy[" + name + "]";
	}

	// -----------------------------------------------------------------------
	/**
	 * Force file deletion strategy.
	 */
	static class ForceFileDeleteStrategy extends FileDeleteStrategy {
		/** Default Constructor */
		ForceFileDeleteStrategy() {
			super("Force");
		}

		/**
		 * Deletes the file object.
		 * <p>
		 * This implementation uses <code>FileUtils.forceDelete() <code>
         * if the file exists.
		 * 
		 * @param fileToDelete
		 *            the file to delete, not null
		 * @return Always returns <code>true</code>
		 * @throws NullPointerException
		 *             if the file is null
		 * @throws IOException
		 *             if an error occurs during file deletion
		 */
		@Override
		protected boolean doDelete(File fileToDelete) throws IOException {
			FileUtils.forceDelete(fileToDelete);
			return true;
		}
	}

}
